/*    file: JniHelper.cpp
 *    desc:
 * 
 * created: 2016-04-11
 *  author: chuanjiang.zh@qq.com
 * company: 
 */

#include "JniHelper.h"

namespace jni
{

Object::Object(JNIEnv *env, const char* className, jobject obj):
    m_env(env),
    m_obj(obj),
    m_clazz(),
    m_className(className)
{
    m_clazz = env->FindClass(className);
}

bool Object::isValid() const
{
    return (m_env && m_clazz && m_obj);
}

jfieldID Object::getFieldID(const char* name, const char* sig)
{
    return m_env->GetFieldID(m_clazz, name, sig);
}

bool Object::getInt(const char* name, jint& value)
{
    jfieldID fieldID = getFieldID(name, "I");
    if (!fieldID)
    {
        return false;
    }

    value = m_env->GetIntField(m_obj, fieldID);
    return true;
}

bool Object::getBool(const char* name, jboolean& value)
{
    jfieldID fieldID = getFieldID(name, "Z");
    if (!fieldID)
    {
        return false;
    }

    value = m_env->GetBooleanField(m_obj, fieldID);
    return true;
}

bool Object::getByte(const char* name, jbyte& value)
{
    jfieldID fieldID = getFieldID(name, "B");
    if (!fieldID)
    {
        return false;
    }

    value = m_env->GetByteField(m_obj, fieldID);
    return true;
}

bool Object::getChar(const char* name, jchar& value)
{
    jfieldID fieldID = getFieldID(name, "C");
    if (!fieldID)
    {
        return false;
    }

    value = m_env->GetCharField(m_obj, fieldID);
    return true;
}

bool Object::getShort(const char* name, jshort& value)
{
    jfieldID fieldID = getFieldID(name, "S");
    if (!fieldID)
    {
        return false;
    }

    value = m_env->GetShortField(m_obj, fieldID);
    return true;
}

bool Object::getLong(const char* name, jlong& value)
{
    jfieldID fieldID = getFieldID(name, "J");
    if (!fieldID)
    {
        return false;
    }

    value = m_env->GetLongField(m_obj, fieldID);
    return true;
}

bool Object::getFloat(const char* name, jfloat& value)
{
    jfieldID fieldID = getFieldID(name, "F");
    if (!fieldID)
    {
        return false;
    }

    value = m_env->GetFloatField(m_obj, fieldID);
    return true;
}

bool Object::getDouble(const char* name, jdouble& value)
{
    jfieldID fieldID = getFieldID(name, "D");
    if (!fieldID)
    {
        return false;
    }

    value = m_env->GetDoubleField(m_obj, fieldID);
    return true;
}

bool Object::getObject(const char* name, const char* sig, jobject& obj)
{
    jfieldID fieldID = getFieldID(name, sig);
    if (!fieldID)
    {
        return false;
    }

    obj = m_env->GetObjectField(m_obj, fieldID);
    return true;
}

bool Object::getByteArray(const char* name, jbyteArray& arr)
{
    jfieldID fieldID = getFieldID(name, "[B");
    if (!fieldID)
    {
        return false;
    }

    arr = reinterpret_cast<jbyteArray>(m_env->GetObjectField(m_obj, fieldID));
    return true;
}

bool Object::getByteArray(const char* name, std::string& str)
{
	jbyteArray arr;
	if (!getByteArray(name, arr))
	{
		return false;
	}

	ByteArray byteArray(m_env, arr);
	if (byteArray.length() > 0)
	{
		str.assign((char*)byteArray.element(), byteArray.length());
	}
	return true;
}

bool Object::setInt(const char* name, jint value)
{
    jfieldID fieldID = getFieldID(name, "I");
    if (!fieldID)
    {
        return false;
    }

    m_env->SetIntField(m_obj, fieldID, value);
    return true;
}


bool Object::setBool(const char* name, jboolean value)
{
    jfieldID fieldID = getFieldID(name, "Z");
    if (!fieldID)
    {
        return false;
    }

    m_env->SetBooleanField(m_obj, fieldID, value);
    return true;
}

bool Object::setByte(const char* name, jbyte value)
{
    jfieldID fieldID = getFieldID(name, "B");
    if (!fieldID)
    {
        return false;
    }

    m_env->SetByteField(m_obj, fieldID, value);
    return true;
}

bool Object::setChar(const char* name, jchar value)
{
    jfieldID fieldID = getFieldID(name, "C");
    if (!fieldID)
    {
        return false;
    }

    m_env->SetCharField(m_obj, fieldID, value);
    return true;
}

bool Object::setShort(const char* name, jshort value)
{
    jfieldID fieldID = getFieldID(name, "S");
    if (!fieldID)
    {
        return false;
    }

    m_env->SetShortField(m_obj, fieldID, value);
    return true;
}

bool Object::setLong(const char* name, jlong value)
{
    jfieldID fieldID = getFieldID(name, "J");
    if (!fieldID)
    {
        return false;
    }

    m_env->SetLongField(m_obj, fieldID, value);
    return true;
}

bool Object::setFloat(const char* name, jfloat value)
{
    jfieldID fieldID = getFieldID(name, "F");
    if (!fieldID)
    {
        return false;
    }

    m_env->SetFloatField(m_obj, fieldID, value);
    return true;
}

bool Object::setDouble(const char* name, jdouble value)
{
    jfieldID fieldID = getFieldID(name, "D");
    if (!fieldID)
    {
        return false;
    }

    m_env->SetDoubleField(m_obj, fieldID, value);
    return true;
}

bool Object::setObject(const char* name, const char* sig, jobject value)
{
	jfieldID fieldID = getFieldID(name, sig);
	if (!fieldID)
	{
		return false;
	}

	m_env->SetObjectField(m_obj, fieldID, value);
	
	return true;
}

bool Object::setByteArray(const char* name, jbyteArray& arr)
{
	return setObject(name, "[B", arr);
}





ByteArray::ByteArray(JNIEnv *env, jbyteArray arr):
m_env(env),
m_arr(arr),
m_element()
{
}

ByteArray::~ByteArray()
{
    release();
}

jsize ByteArray::length()
{
    if (!m_arr)
    {
        return 0;
    }
    return m_env->GetArrayLength(m_arr);
}

jbyte* ByteArray::element()
{
    if (!m_arr)
    {
        return NULL;
    }

    if (m_element == NULL)
    {
        m_element = m_env->GetByteArrayElements(m_arr, NULL);
    }
    return m_element;
}

void ByteArray::release()
{
    if (m_arr && m_element)
    {
        m_env->ReleaseByteArrayElements(m_arr, m_element, 0);
        m_element = NULL;
    }
}


UtfString::UtfString(JNIEnv *env, jstring str):
m_env(env),
m_str(str),
m_element()
{
}

UtfString::~UtfString()
{
    release();
}

const char* UtfString::c_str()
{
    if (m_element == NULL)
    {
        m_element = m_env->GetStringUTFChars(m_str, NULL);
    }
    return m_element;
}

jsize UtfString::length()
{
    return m_env->GetStringLength(m_str);
}

void UtfString::release()
{
    if (m_element)
    {
        m_env->ReleaseStringUTFChars(m_str, m_element);
        m_element = NULL;
    }
}


jstring JniHelper::toString(JNIEnv* env, const char* sz)
{
	jclass strClass = env->FindClass("Ljava/lang/String;");
	jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
	jbyteArray bytes = env->NewByteArray(strlen(sz));
	env->SetByteArrayRegion(bytes, 0, strlen(sz), (jbyte*)sz);
	jstring encoding = env->NewStringUTF("utf-8");
	return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
}

void JniHelper::setAt(JNIEnv* env, jintArray arr, int idx, int value)
{
	jboolean isCopy = false;
	jsize length = env->GetArrayLength(arr);
	if (idx < length)
	{
		jint* elements = env->GetIntArrayElements(arr, &isCopy);
		elements[idx] = value;
		env->ReleaseIntArrayElements(arr, elements, 0);
	}
}

void JniHelper::setAt(JNIEnv* env, jlongArray arr, int idx, int64_t value)
{
	jboolean isCopy = false;
	jsize length = env->GetArrayLength(arr);
	if (idx < length)
	{
		jlong* elements = env->GetLongArrayElements(arr, &isCopy);
		elements[idx] = value;
		env->ReleaseLongArrayElements(arr, elements, 0);
	}
}


}
